/*
* Copyright (c) 2017 Zhangyujie (Tocy)

* This file is part of PlayerDemo project.
*/

#include "RenderYuv.h"
#include <cstdio>
#include <cassert>

#define LOGE printf

YuvRenderer::YuvRenderer()
    : m_sdl_window(NULL)
    , m_sdl_renderer(NULL)
    ,m_in_width(0), m_in_height(0)
   , m_show_texture(NULL)
{
    m_show_rect.x = m_show_rect.y = 0;
    m_show_rect.w = m_show_rect.h = 0;
}

YuvRenderer::~YuvRenderer()
{
    Uninit();
}

bool YuvRenderer::Init(SDL_Rect show_rect)
{
    if (SDL_TRUE == SDL_RectEmpty(&show_rect))
    {
        LOGE("%s %d invalid showrect\n", __FUNCTION__, __LINE__);
        return false;
    }

    if (NULL != m_sdl_window)
    {
        return true;
    }

    // 查询VIDEO子系统是否初始化，如果没有的话，初始化
    if (0 == SDL_WasInit(SDL_INIT_VIDEO))
    {
        SDL_InitSubSystem(SDL_INIT_VIDEO);
    }

    m_sdl_window = SDL_CreateWindow("sdl2 window", show_rect.x, show_rect.y,
        //SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        show_rect.w, show_rect.h, 
        0/*SDL_WINDOW_RESIZABLE|SDL_WINDOW_BORDERLESS*/);
    if (NULL == m_sdl_window)
    {
        LOGE("SDL_CreateWindow failed error %s\n", SDL_GetError());
        return false;
    }

    m_sdl_renderer = SDL_CreateRenderer(m_sdl_window, -1, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
    if (NULL == m_sdl_renderer)
    {
        LOGE("%s %d SDL_CreateRenderer failed error %s\n", __FUNCTION__, __LINE__, SDL_GetError());
        return false;
    }

    m_show_rect = show_rect;

    return true;
}
void YuvRenderer::Uninit()
{
    if (NULL != m_show_texture)
    {
        SDL_DestroyTexture(m_show_texture);
        m_show_texture = NULL;
    }

    if (NULL != m_sdl_renderer)
    {
        SDL_DestroyRenderer(m_sdl_renderer);
        m_sdl_renderer = NULL;
    }

    if (NULL != m_sdl_window)
    {
        SDL_DestroyWindow(m_sdl_window);
        m_sdl_window = NULL;
    }
}

bool YuvRenderer::CreateTexture(int width, int height)
{
    if (m_in_height == height && m_in_width == width &&
        NULL != m_show_texture)
    {
        return true;
    }

    assert(width > 0 && width < 10000);
    assert(height > 0 && height < 10000);

    m_show_texture = SDL_CreateTexture(m_sdl_renderer, SDL_PIXELFORMAT_IYUV, 
        SDL_TEXTUREACCESS_STREAMING, width, height);
    if (NULL != m_show_texture)
    {
        m_in_width = width;
        m_in_height = height;
    }
    else
    {
        LOGE("%s %d create texutre failed err %s\n", __FUNCTION__, __LINE__, SDL_GetError());
    }

    return NULL != m_show_texture;
}
void YuvRenderer::FillTexture(unsigned char *data[3], int stride[3])
{
    void * pixel = NULL;
    int pitch = 0;
    if(0 == SDL_LockTexture(m_show_texture, NULL, &pixel, &pitch))
    {
        // for Y
        int h = m_in_height;
        int w = m_in_width;
        unsigned char * dst = reinterpret_cast<unsigned char *>(pixel);
        unsigned char * src = data[0];
        for (int i = 0; i < h; ++i)
        {
            memcpy(dst, src, w);
            dst += pitch;
            src += stride[0];
        }

        h >>= 1;
        w >>= 1;
        pitch >>= 1;
        // for U
        for (int i = 0; i < h; ++i)
        {
            memcpy(dst, src, w);
            dst += pitch;
            src += stride[1];
        }

        // for V
        for (int i = 0; i < h; ++i)
        {
            memcpy(dst, src, w);
            dst += pitch;
            src += stride[2];
        }
        SDL_UnlockTexture(m_show_texture);
    }
}

void YuvRenderer::Update(int width, int height, unsigned char * data[3], int stride[3])
{
    if (NULL == m_show_texture)
    {
        CreateTexture(width, height);
    }

    if (NULL != m_show_texture)
    {
        FillTexture(data, stride);
    }
}

bool YuvRenderer::Render()
{
    if (NULL != m_show_texture)
    {
        SDL_RenderCopy(m_sdl_renderer, m_show_texture, NULL, NULL);    
        SDL_RenderPresent(m_sdl_renderer); 
    }

    return true;
}